#include "Restaurant.h"
#include <string.h>


/********************************************/
/*RestaurantSystem							*/
/********************************************/
RestaurantSystem::RestaurantSystem() {
	customers = new CustomerDataBase;
	orders = new OrderDataBase;
};

RestaurantSystem::~RestaurantSystem() {
	delete customers;
};

ErrorType RestaurantSystem::addCustomer(const char * name) {
	Customer *customer = new Customer(name);
	Order *order  = NULL;

	if (customer == NULL) {
		return MEMORY_ERROR;
	}
	ErrorType res = customers->addCustomer(*customer);
	if (res!=OK) return res;

	res = customer->getOrder(&order);
	if (res!=OK) return res;

	res = orders->addOrder(*order);
	if (res!=OK) return res;
	return OK;
};

ErrorType RestaurantSystem::deleteCustomer(const char *name){
	Customer *customer = NULL;
	ErrorType res = getCustomer(name, &customer);
	if (res != OK) return res;
	
	Order *order = NULL;
	res = customer->getOrder(&order);
	if (res != OK) return res;

	res = orders->removeOrder(*order);
	if (res != OK) return res;

	return customers->removeCustomer(*customer);
};

ErrorType RestaurantSystem::order(const char *name, DrinkType drink, FirstType first, MainType main, DesertType desert){
	Customer *customer = NULL;
	ErrorType res = getCustomer(name, &customer);
	if (res != OK) return res;

	return customer->order(drink, first, main, desert);
};

ErrorType RestaurantSystem::getOrder(const char *name, DrinkType &drink, FirstType &first, MainType &main, DesertType &desert) const{
	Customer *customer = NULL;
	ErrorType res = getCustomer(name, &customer);
	if (res != OK) return res;
	return customer->getOrder(drink, first, main, desert);
};

ErrorType RestaurantSystem::getCustomer(const char *name, Customer **customer) const{
	return customers->getCustomer(name, customer);
};

/********************************************/
/*CustomerDataBase							*/
/********************************************/

CustomerDataBase::CustomerDataBase(){
	nofCustomers = 0;
	arraySize = EXPAND_VALUE;
	customers = new Customer*[EXPAND_VALUE];
};

CustomerDataBase::~CustomerDataBase(){
	int i;
	for (i=0; i<nofCustomers; i++){
		delete customers[i];
	}
	delete[] customers;
};

ErrorType CustomerDataBase::addCustomer(Customer& customer){
	if (nofCustomers >= arraySize){
		ErrorType res = expandDataBase();
		if (res!=OK) return res;
	}

	const char *name1 = NULL, *name2 = NULL;
	/*search for already exist customer*/
	for (int i=0; i<nofCustomers; i++) {
		name1 = customers[i]->getName();
		name2 = customer.getName();
		if (strcmp(name1, name2) == 0) {
			return ALREADY_EXIST_ERROR;
		}
	}
	customers[nofCustomers++] = &customer;
	return OK;
};

ErrorType CustomerDataBase::removeCustomer(Customer& customer){
	int i=0;
	for (i=0; i<nofCustomers; i++){
		if (customers[i] == &customer){
			delete &customer;
			shiftLeft(i);
			nofCustomers--;
			return OK;
		}
	}
	return NOT_FOUND_ERROR;
};

ErrorType CustomerDataBase::shiftLeft(int i)
{
	int j;
	for (j=i; j<nofCustomers-1; j++)
	{
		customers[j] = customers[j+1];
	}
	return OK;
};

ErrorType CustomerDataBase::expandDataBase()
{
	Customer **newCustomers = new Customer*[arraySize + EXPAND_VALUE];
	if (newCustomers == NULL) {
		return MEMORY_ERROR;
	}
	for (int i = 0; i < nofCustomers; i++) {
		newCustomers[i] = customers[i];
	}

	delete[] customers;
	customers = newCustomers;
	arraySize += EXPAND_VALUE;
	return OK;
};

ErrorType CustomerDataBase::reduceDataBase(){
	Customer **newCustomers = new Customer*[arraySize - EXPAND_VALUE];
	if (newCustomers == NULL) {
		return MEMORY_ERROR;
	}
	for (int i = 0; i < nofCustomers; i++) {
		newCustomers[i] = customers[i];
	}

	delete[] customers;
	customers = newCustomers;
	arraySize -= EXPAND_VALUE;
	return OK;
};

ErrorType CustomerDataBase::getCustomer(const char *name, Customer **customer) const{
	const char *name1 = NULL;
	/*search for already exist customer*/
	for (int i=0; i<nofCustomers; i++) {
		name1 = customers[i]->getName();
		if (strcmp(name1, name) == 0) {
			*customer = customers[i];
			return OK;
		}
	}
	return NOT_FOUND_ERROR;
}

/********************************************/
/*OrderDataBase							*/
/********************************************/

OrderDataBase::OrderDataBase(){
	nofOrders = 0;
	arraySize = EXPAND_VALUE;
	orders = new Order*[EXPAND_VALUE];
};

OrderDataBase::~OrderDataBase(){
	int i;
	for (i=0; i<nofOrders; i++){
		delete orders[i];
	}
	delete[] orders;
};

ErrorType OrderDataBase::addOrder(Order& order){
	if (nofOrders >= arraySize){
		ErrorType res = expandDataBase();
		if (res!=OK) return res;
	}
	orders[nofOrders++] = &order;
	return OK;
};

ErrorType OrderDataBase::removeOrder(Order& order){
	int i=0;
	for (i=0; i<nofOrders; i++){
		if (orders[i] == &order){
			delete &order;
			shiftLeft(i);
			nofOrders--;
			return OK;
		}
	}
	return NOT_FOUND_ERROR;
};

ErrorType OrderDataBase::shiftLeft(int i)
{
	int j;
	for (j=i; j<nofOrders-1; j++)
	{
		orders[j] = orders[j+1];
	}
	return OK;
};

ErrorType OrderDataBase::expandDataBase()
{
	Order **newOrders = new Order*[arraySize + EXPAND_VALUE];
	if (newOrders == NULL) {
		return MEMORY_ERROR;
	}
	for (int i = 0; i < nofOrders; i++) {
		newOrders[i] = orders[i];
	}

	delete[] orders;
	orders = newOrders;
	arraySize += EXPAND_VALUE;
	return OK;
};

ErrorType OrderDataBase::reduceDataBase(){
	Order **newOrders = new Order*[arraySize - EXPAND_VALUE];
	if (newOrders == NULL) {
		return MEMORY_ERROR;
	}
	for (int i = 0; i < nofOrders; i++) {
		newOrders[i] = orders[i];
	}

	delete[] orders;
	orders = newOrders;
	arraySize -= EXPAND_VALUE;
	return OK;
};


/********************************************/
/*Customer									*/
/********************************************/

Customer::Customer(const char * name){
	this->name = name;
	orderInstance = new Order(this);
	orderInstance->setOrder(NODRINK, NOFIRST, NOMAIN, NODESERT);
};

Customer::~Customer(){};

ErrorType Customer::order(DrinkType drink, FirstType first, MainType main, DesertType desert) {
	return orderInstance->setOrder(drink, first, main, desert);
};

ErrorType Customer::getOrder(DrinkType &drink, FirstType &first, MainType &main, DesertType &desert) const {
	return orderInstance->getOrder(drink, first, main, desert);
};

ErrorType Customer::getOrder(Order **order) const {
	*order = orderInstance;
	return OK;
};

const char *Customer::getName() const{
	return this->name;
};

/********************************************/
/*Order										*/
/********************************************/
Order::Order(Customer *customer){
	this->customer = customer;
	this->drink = NODRINK;
	this->main = NOMAIN;
	this->desert = NODESERT;
	this->first = NOFIRST;
};

ErrorType Order::setOrder(DrinkType drink, FirstType first, MainType main, DesertType desert){
	this->drink = drink;
	this->first = first;
	this->desert = desert;
	this->main = main;
	return OK;
};

Order::~Order() {
};

ErrorType Order::getOrder(DrinkType &drink, FirstType &first, MainType &main, DesertType &desert) const{
	drink = this->drink;
	first = this->first;
	desert = this->desert;
	main = this->main;
	return OK;
};